#!/usr/bin/env python

from liwe.module import LiweModule
import sys, os, mimetypes , stat , time, inspect

#NOTE: add this values to liwe.cfg for custom functionalities.
"""
# ==========================================
# Download manager tables definition 
# ==========================================
DOWNLOAD_MANAGER_MODULE_CONDITION=	module name on which to use extra params
DOWNLOAD_MANAGER_EXTRA_TABLE=		extra table used for custom search
DOWNLOAD_MANAGER_ID_FIELD=		extra table id which will be id_obj in download_manager table 
DOWNLOAD_MANAGER_BROWSE_FILE=		ajax request to call for custom search
DOWNLOAD_MANAGER_ADD_FILE=		ajax request for adding extra datas
DOWNLOAD_MANAGER_EDIT_FILE=		ajax request for updating extra datas
DOWNLOAD_MANAGER_REMOVE_FILE=		ajax request when deleting files
"""
# define costants
EXT_IMGS = [ "gif", "png", "jpg", "jepg" ]
EXT_ARCH = [ "zip", "tar", "rar", "gz", "7z", "sit", "sitd", "sit5", "iso" ]
EXT_EXE  = [ "exe", "sh", "app" ]
EXT_PDF  = [ "pdf" ]
EXT_DOC  = [ "doc", "txt", "exl", "xls", "bin", "inc", "php", "html", "odt", "py", "css", "js", "calc", "mp3" ]
ICON_SIZE = 150;

class DownloadManager ( LiweModule ):
	def __init__ ( self, liwe ):
		super ( DownloadManager, self ).__init__ ( liwe, "download_manager" )

	def _get_func_args ( self, func = None, kwargs = None ):

		args = inspect.getargspec ( func ) [ 0 ]
		args [:] = ( val for val in args if val != 'self' and val != 'kwargs' )
		#sys.stderr.write ( "\n------------------ DOWNLOAD_MANAGER _get_func_args args : %s \n" % args )
		#FIXME: se viene passato kwargs eliminare le chiavi che hanno un valore
		"""
		if kwargs:
			args [:] = ( val for val in args if kwargs.get ( val ) )
			sys.stderr.write ( "\n------------------ DOWNLOAD_MANAGER _get_func_args ( kwargs ) args : %s \n" % args )
		"""
		return args
		
	# admin functions
	def add_file ( self, file_obj, name = "", descr = "", files_tags = "", id_file = 0, id_obj = 0, module = "", update = "", kwargs = None ):


		if not module: module = 'download_manager'	

		if not update:
			unique_id = self._create_id ()
		else:
			unique_id = id_file

		#injection
		inj = self.cfg.get ( "add_file" )
		extra_mod = self.cfg.get ( 'module_condition', 'download_manager' )
		if inj and module == extra_mod:
			# for compatibility with older versions
			#if id_obj: kwargs [ 'id_obj' ] = id_obj
			# add to kwargs defined params
			arg_lst = self._get_func_args ( self.add_file )
			[ kwargs.update ( { arg : locals () [ arg ] } ) for arg in arg_lst ]
			kwargs [ 'id_file' ] = unique_id 

			inj_res = self.liwe.invoke ( inj, ** kwargs )
			id_obj = inj_res.get ( 'id_obj' )

		if not update:
			#unique_id = self._create_id ()
			fname = self._get_dir_name ( unique_id )

			if not name: name = file_obj [ 'filename' ]
			fil = file_obj [ 'file' ]
			fil.seek ( 0, os.SEEK_END )
			size = fil.tell ()
			fil.seek ( 0 )


			split = os.path.splitext ( file_obj [ 'filename' ] )
			if split:
				ext = split [ 1 ] [ 1 : ]
			else:
				ext = ""

			ext = ext.lower ()

			fout_name = os.path.join ( fname, "%s.%s" % ( unique_id, ext ) )
			fout = open ( fout_name, "wb" )
			fout.write ( fil.read () )
			fout.close ()

			self._create_thumb ( fname, unique_id, fout_name, ext )

			dct = { "name" : name, "descr" : descr, "fsize" : size, "fext" : ext, "uid" : 0, "id_obj" : id_obj, "module" : module }
		else:
			dct = { "name" : name, "descr" : descr }
			#unique_id = id_file
 

		self.dbm.update ( "download_manager", dct, "id = %s" % unique_id )

		# TAGS
		#sys.stderr.write ( "\n\n\n\n\n**----------------- DOWNLOAD_MANAGER add_file: files_tags = %s\n\n\n\n\n " % files_tags )
		self.liwe.invoke ( "tags.admin.del_all_tags", id_obj = unique_id, id_site = self.site_id, module = module )
                self.liwe.invoke ( "tags.ajax.tag_object", id_obj = unique_id, id_site = self.site_id, tags = files_tags, module = module )

	def edit_file ( self, id_file = 0, id_obj = 0, module = "", action = "", kwargs = {} ):

		if not module:
			module = 'download_manager'	
		#res = self.browse_files ( id_file = id_file , id_obj = id_obj, name = '' , descr = '', filters_tags = '', fext = '', page_view = '', order_by = '', 
		res = self.browse_files ( id_file = id_file , id_obj = id_obj, module = module, start_pos = 0, limit = 1, kwargs = kwargs ) [ 'results' ] 
		if res:
			#tag objects
                	tags_str = ''
                	if id_file:

                        	tgs = self.liwe.invoke ( "tags.ajax.tags_list", id_obj = id_file, id_site = self.site_id, 
							 module = module, id_only = 0, names_only = 1 ) [ 'tags' ]

				dct = { "id_file" : id_file, "id_obj" : res [ 0 ][ 'id_obj' ], "name" : res [ 0 ][ 'name' ] , "descr" : res [ 0 ][ 'descr' ], "files_tags" : tgs }
				
				inj = self.cfg.get ( 'edit_file' )
				extra_mod = self.cfg.get ( 'module_condition', 'download_manager' )
				if inj and module == extra_mod:
					if not kwargs:
						rel_id = self.cfg.get ( 'id_field' )
						kwargs [ rel_id ] = dct [ 'id_obj' ]

					inj_res = self.liwe.invoke ( inj, ** kwargs )
					if inj_res:
						dct.update ( inj_res.get ( 'row' ) )
				return dct

		return {}


	def _create_id ( self ):
		self.dbm.insert ( "download_manager", { "created" : "*NOW()" } )
		return self.dbm.insert_id ()

	def _get_dir_name ( self, unique_id ):
		main_dir = "%3.3d" % ( unique_id % 1000 )
		sub_dir  = "%2.2d" % ( unique_id % 100 )

		my_path = os.path.join ( "site", "download_manager", main_dir, sub_dir )

		if not os.path.isdir ( my_path ): os.makedirs ( my_path )

		return my_path

	def _create_thumb ( self, path_name, unique_id, full_dest_name, ext ):
		if not ext: 
			icon_path = os.path.join ( "site", "download_manager", "icons", "none.png" )
                        self._create_thumb_image ( path_name, unique_id, icon_path )
			return
		
		if ext in EXT_IMGS:
			self._create_thumb_image ( path_name, unique_id, full_dest_name )

		elif ext in EXT_ARCH:
			icon_path = os.path.join ( "site", "download_manager", "icons", "zip.png" )
			self._create_thumb_image ( path_name, unique_id, icon_path )

		elif ext in EXT_EXE:
			icon_path = os.path.join ( "site", "download_manager", "icons", "exe.png" )
			self._create_thumb_image ( path_name, unique_id, icon_path )

		elif ext in EXT_DOC:
                        icon_path = os.path.join ( "site", "download_manager", "icons", "document.png" )
                        self._create_thumb_image ( path_name, unique_id, icon_path )
		
		elif ext in EXT_PDF:
			fout_name = os.path.join ( path_name, "%s.%s%s" % ( unique_id , ext, "[0]" ) )
			icon_path = os.path.join ( path_name, "thumb_%s.jpg" % unique_id ) 
			os.system ( "convert -geometry %dx%d %s %s " % ( ICON_SIZE, ICON_SIZE, fout_name, icon_path ) )
		else:
			icon_path = os.path.join ( "site", "download_manager", "icons", "none.png" )
                        self._create_thumb_image ( path_name, unique_id, icon_path )
		

	def _create_thumb_image ( self, path_name, unique_id, full_dest_name ):
		from os3.utils.image_handler import ImageHandler

		ih = ImageHandler ()
		im = ih.load ( full_dest_name )
		im.toRGB ()
		im.scale ( ICON_SIZE, ICON_SIZE )
		im.save ( os.path.join ( path_name, "thumb_%s.jpg" % unique_id ), "JPEG" )

	def _define_mime_type ( self, path_name = '' ):
		mimetypes.init ()
		mime = mimetypes.guess_type ( path_name )
		return mime

	def remove_file ( self , path_name = '', id_file = 0, id_obj = 0, module = '', kwargs = {} ):
 
		#sys.stderr.write ( "DOWNLOAD_MANAGER_REMOVE_FILE path_name: %s, id: %s, id_obj: %s, module: %s, kwargs: %s \n" % ( path_name , id , id_obj , module , str ( kwargs ) ) )
		if not module:
			module = 'download_manager'	

		inj = self.cfg.get ( 'remove_file' )
		extra_mod = self.cfg.get ( 'module_condition', 'download_manager' )
		if inj and module == extra_mod:
			arg_lst = self._get_func_args ( self.remove_file )
			[ kwargs.update ( { arg : locals () [ arg ] } ) for arg in arg_lst ]
			rel_id = self.cfg.get ( 'id_field' )
			kwargs [ rel_id ] = id_obj
			inj_res = self.liwe.invoke ( inj, ** kwargs )

		# 0: no id, 1: errore del db, 2: errore file system
		if not id_file:
			return 0

		conds = " id = %s " % id_file
		#self.dbm.debug = sys.stderr.write
		db = self.dbm.delete ( 'download_manager', conds )
		#self.dbm.debug = None
		if not db:
			return 1
		# TAGS elimina tags relativi al file
		self.liwe.invoke ( "tags.admin.del_all_tags", id_obj = id_file, id_site = self.site_id, module = module )

		while True :
			try:
				os.remove ( path_name )
				break
			except:
				return 2

	# user functions

	def browse_files ( self, id_file = 0, name = '' , descr = '', filters_tags = '', fext = '', page_view = '', id_obj = 0, module = '', order_by = '', start_pos = 0, limit = 10, kwargs = None ):
		conds = []
		clause = ''
		res = {}
		if not module:
			module = 'download_manager'	
		#FIXME: modifica dependency injection
		inj = self.cfg.get ( 'browse_file' )
		extra_mod = self.cfg.get ( 'module_condition', 'download_manager' )
		if inj and module == extra_mod:
			inj_res = self.liwe.invoke ( inj, ** kwargs )
			extra_ids = inj_res.get ( 'ids' )
			if not id_obj and not extra_ids: 
				return { "results" : [], "rows" : 0 }

			if id_obj:
				extra_ids.append ( id_obj )
			if extra_ids:
				id_obj = ','.join ( extra_ids )
			
 
		if not order_by: order_by = 'name'
		if id_file: conds.append ( "id = %s " % id_file )
		if id_obj: conds.append ( "id_obj IN ( %s ) " % id_obj )

		if module and not id_file: conds.append ( "module = '%s' " % module )
		if name: conds.append ( "name LIKE '%%%s%%' " % name )
		if descr: conds.append ( "descr LIKE '%%%s%%' " % descr )
		if fext: conds.append ( "fext = '%s' " % fext )
		if filters_tags:
			tgs = self.liwe.invoke ( "tags.ajax.search", tag_names = filters_tags, id_site = self.site_id, module = module ) [ 'tags' ]

			ids = [ str ( t [ 'id_obj' ] ) for t in tgs ]

			if not ids: 
				return  { "results" : [] , "rows" : 0 }

			if ids:
				conds.append ( "id IN ( %s )" % ",".join ( ids ) )		


		clause = " AND ".join ( conds )

		extras = " ORDER BY %s " % order_by
		extras += " LIMIT %d,%d " % ( start_pos, limit )

		#self.dbm.debug = sys.stderr.write
		tot_rows = self.dbm.count ( 'download_manager' , 'id' , clause )
		res = self.dbm.all_rows ( "download_manager", [ 'id', 'created', 'name', 'descr', 'fext', 'id_obj', 'module' ], clause, extras = extras, debug = True )
		
		if res:
			for r in res:
				dir = self._get_dir_name (  r [ 'id' ] )
				file_path =  "%s/%s.%s" % ( dir, r [ 'id' ], r [ 'fext' ] )

				r [ 'path' ] = dir
				r [ 'mime' ] = self._define_mime_type ( file_path )

				if page_view == 'details':
					details = self.file_details ( file_path , r [ 'module' ] )
					r.update ( details )

			"""			
			if page_view == 'details':
				for r in res:
					dir = self._get_dir_name (  r [ 'id' ] )
					details = self.file_details ( "%s/%s.%s" % ( dir, r [ 'id' ], r [ 'fext' ] ), r [ 'id' ], r [ 'module' ] )
					r.update ( details )
			"""
			return  { "results" : res, "rows" : tot_rows }
		
		res = {}

		return  { "results" : res, "rows" : tot_rows }
	
	def file_details ( self , path_name = '', id_file = 0, module = '' ):

		if not module:
                        module = 'download_manager'
		fileStats = os.stat ( path_name )
		#tag objects
		tags_str = ''
		if id_file:
			tgs = self.liwe.invoke ( "tags.ajax.tags_list", id_obj = id_file, id_site = self.site_id, module = module, id_only = 0 ) [ 'tags' ]
			
                        tgs_names = [ str ( t [ 'name' ] ) for t in tgs ]
                        if tgs_names:
                                tags_str =  ", ".join ( tgs_names ) 		


		fileInfo = {

		   'Size' : fileStats [ stat.ST_SIZE ],

		   'LastModified' : time.ctime ( fileStats [ stat.ST_MTIME ] ),

		   'LastAccessed' : time.ctime ( fileStats [ stat.ST_ATIME ] ),

		   'CreationTime' : time.ctime ( fileStats [ stat.ST_CTIME ] ),

		   'Mode' : fileStats [ stat.ST_MODE ],
	
		   'Tags' : tags_str

		}

		return fileInfo

	def download_file ( self, path_name = '', file_name = '' ):
		data = open ( path_name, "rb" ).read ()
		mime = self._define_mime_type ( path_name )

		self.liwe.pyhp.set_header (  'Content-Type', "application/octet-stream" ) #mime [ 0 ] )
		# FIXME: i valori devono essere string
		self.liwe.pyhp.set_header (  'Content-Length', str ( len ( data ) ) )
		self.liwe.pyhp.set_header (  'Content-Transfer-Encoding', "binary" )
		self.liwe.pyhp.set_header (  'Content-Disposition', 'attachment; filename="%s"' % file_name )
		
		print data

	def _get_ext_list ( self ):
		res = self.dbm.all_rows ( "download_manager", "fext", extras = "GROUP BY fext" )
		if res:
			return res
		return {}		

	def _get_mods_list ( self ):
		res = self.dbm.all_rows ( "download_manager", "module", extras = "GROUP BY module" )
		if res:
			return res
		return {}		
